// <copyright file="SettingService.cs" company="Clever Software">
// Copyright (c) 2013, 2014 All Right Reserved, http://www.cleversoftware.by
//
// This source is subject to the Microsoft Permissive License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Clever Software</author>
// <email>info@cleversoftware.by</email>
// <date>2014-02-04</date> 
// <summary>CleverCMS source code</summary>

namespace CleverCMS.Cms.Services
{
    using System;
    using System.Linq;
    using System.Web.Caching;
    using System.Web.Configuration;

    using Cms.Data;
    using Cms.Data.Entities;
    using Core.Configuration;
    using Core.Extensions;
    using Core.Infrastructure;

    public class SettingService
    {
        private const string settingCacheKey = "__CleverCmsCacheKey_";
        private readonly IConfigurationAdapter  m_configurationAdapter;
        private readonly ISettingRepository     m_settingRepo;
        private readonly AppCache appCache;

        public SettingService(ISettingRepository        settingData, 
                              IConfigurationAdapter     configurationAdapter)
        {
            this.m_settingRepo = settingData;
            this.m_configurationAdapter = configurationAdapter;
            this.appCache = new AppCache();
        }
        /// <summary>
        /// Return setting by id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public CmsSetting Load(int id)
        {
            return m_settingRepo.Load(id);
        }
        /// <summary>
        /// Return setting by name
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public CmsSetting Load(string key)
        {
            return m_settingRepo.Get(key);
        }
        /// <summary>
        /// Returns all settings
        /// </summary>
        /// <returns></returns>
        public IQueryable<CmsSetting> LoadAll()
        {
            return m_settingRepo.LoadAll();
        }
        /// <summary>
        /// Returns all settings for a paged list
        /// </summary>
        /// <param name="start"></param>
        /// <param name="size"></param>
        /// <param name="sortOrder"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public IQueryable<CmsSetting> LoadAll(int start, int size, string sortOrder, out int count)
        {
            var pages = m_settingRepo.LoadAll(orderBy: q => q.OrderByDescending(d => d.Key))
                                     .Skip(start)
                                     .Take(size);

            count = m_settingRepo.Count();

            return pages;
        }
        /// <summary>
        /// Update setting
        /// </summary>
        /// <param name="cmsSetting"></param>
        public void Update(CmsSetting cmsSetting)
        {
            m_settingRepo.Save(cmsSetting, cmsSetting.Id == 0);
            appCache.Remove("AdminSettings");
        }
        /// <summary>
        /// Delete setting
        /// </summary>
        /// <param name="id"></param>
        public void Delete(int id)
        {
            m_settingRepo.Delete(id);
            appCache.Remove("AdminSettings");
        }
        /// <summary>
        /// Return value of the setting
        /// </summary>
        /// <param name="settingKey"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        public string GetSettingValue(string settingKey, Cache cache)
        {
            string settingFromCache = GetFromCache(settingKey, cache);
            
            if (null != settingFromCache)
                return settingFromCache;

            CmsSetting setting = m_settingRepo.Get(settingKey);
            if (null == setting)
            {
                CacheSetting(settingKey, string.Empty, cache);
                return string.Empty;
            }

            CacheSetting(settingKey, setting.Value, cache);
            return setting.Value;
        }
        /// <summary>
      
        //TODO: Workout a general caching strategy
        
        /// Cache setting
        /// </summary>
        /// <param name="settingKey"></param>
        /// <param name="settingValue"></param>
        /// <param name="cache"></param>
        private void CacheSetting(string settingKey, string settingValue, Cache cache)
        {
            settingValue = settingValue.NullSafe();
            OutputCacheSettingsSection outputCacheSection = m_configurationAdapter.GetSection<OutputCacheSettingsSection>("system.web/caching/outputCacheSettings");
            
            if (outputCacheSection.OutputCacheProfiles.Count > 0)
            {
                OutputCacheProfile profile = outputCacheSection.OutputCacheProfiles.Get("SettingsCacheProfile");
                if (null != profile)
                    cache.Add(settingCacheKey + settingKey, settingValue, null, Cache.NoAbsoluteExpiration, TimeSpan.FromSeconds(profile.Duration), CacheItemPriority.Normal, null);
            }
        }
        /// <summary>
        /// Return setting from cahche
        /// </summary>
        /// <param name="settingKey"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        private string GetFromCache(string settingKey, Cache cache)
        {
            var valueFromCache = cache[settingCacheKey + settingKey] as string;
            
            if (null != valueFromCache)
                return valueFromCache;

            return null;
        }
    }
}